using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Net;
using System.Web.Services.Protocols;
using System.Xml;
using Microsoft.Crm.Sdk.Proxy;

using Microsoft.Win32;

using Microsoft.VisualStudio.TestTools.UnitTesting;



namespace CRM_Perf_BenchMark.DMUnitTest
{
    [TestClass]
    public class ImportUnitTests
    {
        CRMEntity m_user;
        string m_userName = string.Empty;
        string m_domain = string.Empty;
        string m_password = string.Empty;
        string m_organization = string.Empty;
        string m_crmticket = string.Empty;
        NetworkCredential m_nc = null;
        CrmService Proxy = null;
        string m_CrmServer = string.Empty;
        string m_ApiServer = string.Empty;

        TestContext testContextInstance1;

        public TestContext TestContext
        {
            get
            {
                return testContextInstance1;
            }
            set
            {
                testContextInstance1 = value;
            }
        }

        // Need this public property for webservice so that we do not use the default credential
        public System.Net.NetworkCredential NetworkCredential
        {
            get
            {
                return m_nc;
            }
            set
            {
                m_nc = value;
            }
        }

        private static string resultDir = Directory.GetDirectoryRoot(Directory.GetCurrentDirectory()) + @"PerfResult";

        public ImportUnitTests()
        {
           
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        [ClassInitialize()]
        public static void ClassInitialize(TestContext testContext)
        {
            //this is the directory where all perf results are stored
            string perfResultDir = Directory.GetDirectoryRoot(Directory.GetCurrentDirectory()) + @"PerfResult";
            if (!Directory.Exists(perfResultDir))
                Directory.CreateDirectory(perfResultDir);
        }

        // Use TestInitialize to run code before running each test 
        [TestInitialize()]
        public void TestInitialize()
        {
            System.Collections.Hashtable userProps = new System.Collections.Hashtable();

            if (TestContext.Properties.Contains("UserRole"))
            {
                userProps.Add("role", (string)TestContext.Properties["UserRole"]);
            }

            m_user = EntityManager.Instance.GetNextUser(userProps);
            Proxy = new CrmService();

            string[] splits = m_user["domainname"].Split(new char[] { '\\' }, 2, StringSplitOptions.RemoveEmptyEntries);
            if (splits.Length > 1)
            {
                m_domain = splits[0];
                m_userName = splits[1];
            }

            m_CrmServer = m_user["CrmServer"];
            m_ApiServer = m_user["ApiServer"];
            m_password = m_user["userpassword"];
            m_organization = m_user["organizationname"];

            if (!SetupWebService())
            {
                System.Diagnostics.Trace.WriteLine("Setup Web Service did not succeed");
            }
        }

        public bool SetupWebService()
        {
            Proxy.Url = m_ApiServer + "/MSCRMServices/2007/CrmService.asmx";

            Proxy.UnsafeAuthenticatedConnectionSharing = true;
            m_nc = new NetworkCredential(m_userName, m_password, m_domain);
            Proxy.ConnectionGroupName = m_domain + "\\" + m_userName;
            Proxy.Credentials = m_nc;

            CrmAuthenticationToken token = new CrmAuthenticationToken();
            token.OrganizationName = m_organization;
            token.AuthenticationType = AuthenticationType.AD;
            Proxy.CrmAuthenticationTokenValue = token;
            return true;
        }

        // Use TestCleanup to run code after each test has run
        [TestCleanup()]
        public void TestCleanup()
        {
            EntityManager.Instance.FreeEntity(m_user);
            Proxy = null;
        }

        #endregion

        #region Individual Test Cases

        [TestMethod()]
        public void DMUnitTest_Import_ImportExportMap()
        {
            ImportExportMaps();
        }

        [TestMethod()]
        public void DMUnitTest_Import_ImportLeads_2K()
        {
            ImportLeads(2000);
        }

        [TestMethod()]
        public void DMUnitTest_Import_ContactForUpdate_2K()
        {
            ImportContactsForUpdate(2000);
        }

        [TestMethod()]
        public void DMUnitTest_Import_CreateImport()
        {
            CreateImport();
        }

        #endregion

        #region Private Methodes

        private string LoadMap(string mapXml)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(mapXml);
            XmlNode mapNode = doc.SelectSingleNode("/Map");
            mapNode.Attributes["Name"].Value += DateTime.UtcNow.Ticks;

            return doc.InnerXml;
        }

        private void CreateImport()
        {
            string timestamp = DateTime.Now.Ticks.ToString();
            string CSVFile = resultDir + @"\PerfLead_" + timestamp + ".csv";
            string SummaryFile = resultDir + @"\Perf_Import_ImportFile_Create_Summary_" + timestamp + ".log";
            //write logic to create the csv file
            StreamWriter sw = new StreamWriter(CSVFile, false);
            string row = "Topic,Annual Revenue,Business Phone,City,Company Name,Country/Region,Description,E-mail,Est. Close Date,Est. Value,Fax,First Name,Home Phone,Industry,Job Title,Last Name,Lead Source,Middle Name,Mobile Phone,No. of Employees,Other Phone,Pager,Preferred Method of Contact,Priority,Rating,Salutation,Send Marketing Materials,Do not allow E-mails,SIC Code,Web Site";
            sw.WriteLine(row);
            string clocktick = DateTime.Now.Millisecond.ToString();
            string today = DateTime.Today.ToString();
            for (int i = 1; i <= 1000; i++)
            {   //logic to create distinct rows
                row = "Topic" + clocktick + i.ToString() + ",545454544,11111111,Hyderabad,Microsoft,India,Have a nice day!!!,a@a.com," + today + ",23424,44444444,Firstname" + clocktick + i.ToString() + ",22222222,Accounting,Test Manager,Lastname " + clocktick + i.ToString() + ",Advertisement,Middlename " + clocktick + i.ToString() + ",33333333,87878,77777777,99999999,E-mail,Normal,Hot,Sir,1,0,321,www.microsoft.com";
                sw.WriteLine(row);
            }
            sw.Flush();
            sw.Close();

            string configDirKeyPath = "SOFTWARE\\Microsoft\\MSCRM";
            string configDir = null;

            if (Registry.LocalMachine.OpenSubKey(configDirKeyPath) != null)
            {
                RegistryKey regKey = Registry.LocalMachine.OpenSubKey(configDirKeyPath);
                configDir = (string)regKey.GetValue("CRM_Perf_Toolkit_ConfigDir", "c:\\crmstress");
            }
            else
            {
                //setting the default directory of configsettings.xml to c:\crmstress folder
                configDir = "c:\\crmstress";
            }

            string mapXml = LoadMap(configDir + "\\lead.xml");
            Guid importMapId = CreateImportMapforGivenXML(mapXml, true);

            DateTime before = DateTime.Now;

            import testImport = new import();
            testImport.name = "Test Import" + DateTime.Now.Ticks.ToString();
            Guid importId = Proxy.Create(testImport);

            importfile importFile = new importfile();
            importFile.content = ReadCSV(CSVFile);

            importFile.fielddelimitercode = new Picklist(ImportFieldDelimiter.Comma);
            importFile.datadelimitercode = new Picklist(ImportDataDelimiter.Null);
            importFile.isfirstrowheader = new CrmBoolean(true); ;

            Lookup l1 = new Lookup();
            l1.Value = importId;
            importFile.importid = new Lookup("import", importId);
            importFile.sourceentityname = "lead";
            importFile.targetentityname = "lead";

            Lookup l2 = new Lookup();
            l2.Value = importMapId;
            importFile.importmapid = l2;
            importFile.enableduplicatedetection = new CrmBoolean(true);

            Guid importFileId = Proxy.Create(importFile);

            DateTime after = DateTime.Now;
            TimeSpan duration = after - before;
            lock (typeof(StreamWriter))
            {
                StreamWriter logWriter = new StreamWriter(SummaryFile);
                logWriter.WriteLine("Logging test reult for Import and ImportFile creation ...");
                logWriter.WriteLine("-----------------------------------------");
                logWriter.WriteLine("Import and ImportFile creation took {0} milisecond", duration.TotalMilliseconds);
                logWriter.WriteLine("-----------------------------------------");
                logWriter.Flush();
                logWriter.Close();
            }
        }

        private Guid ImportLeads(int noOfRows)
        {
            string timestamp = System.DateTime.Now.Ticks.ToString();
            string CSVFile = resultDir + @"\PerfLead_" + timestamp + ".csv";
            string SummaryFile = resultDir + @"\Perf_Import_" + noOfRows.ToString() + "Leads_Summary_" + timestamp + ".log";
            //write logic to create the csv file
            StreamWriter sw = new StreamWriter(CSVFile, false);
            string row = "Topic,Annual Revenue,Business Phone,City,Company Name,Country/Region,Description,E-mail,Est. Close Date,Est. Value,Fax,First Name,Home Phone,Industry,Job Title,Last Name,Lead Source,Middle Name,Mobile Phone,No. of Employees,Other Phone,Pager,Preferred Method of Contact,Priority,Rating,Salutation,Send Marketing Materials,Do not allow E-mails,SIC Code,Web Site";
            sw.WriteLine(row);
            string clocktick = DateTime.Now.Millisecond.ToString();
            string today = DateTime.Today.ToString();
            for (int i = 1; i <= noOfRows; i++)
            {   //logic to create distinct rows
                row = "Topic" + clocktick + i.ToString() + ",545454544,11111111,Hyderabad,Microsoft,India,Have a nice day!!!,a@a.com," + today + ",23424,44444444,Firstname" + clocktick + i.ToString() + ",22222222,Accounting,Test Manager,Lastname " + clocktick + i.ToString() + ",Advertisement,Middlename " + clocktick + i.ToString() + ",33333333,87878,77777777,99999999,E-mail,Normal,Hot,Sir,1,0,321,www.microsoft.com";
                sw.WriteLine(row);
            }
            sw.Flush();
            sw.Close();

            string configDirKeyPath = "SOFTWARE\\Microsoft\\MSCRM";
            string configDir = null;

            if (Registry.LocalMachine.OpenSubKey(configDirKeyPath) != null)
            {
                RegistryKey regKey = Registry.LocalMachine.OpenSubKey(configDirKeyPath);
                configDir = (string)regKey.GetValue("CRM_Perf_Toolkit_ConfigDir", "c:\\crmstress");
            }
            else
            {
                //setting the default directory of configsettings.xml to c:\crmstress folder
                configDir = "c:\\crmstress";
            }

            string importMapInnerXml = LoadMap( configDir + "\\lead.xml");
            return ImportEntityForGivenMapXMLAndCSVFIle(importMapInnerXml, new string[] { "lead" }, new string[] { CSVFile }, SummaryFile, noOfRows, 0);
        }

        private void ImportContactsForUpdate(int noOfRows)
        {
            Guid[] contactIds = new Guid[noOfRows + 1];

            contact c = new contact();
            c.firstname = "InitialFirstName";
            c.lastname = "InitialLastName";

            for (int i = 1; i <= noOfRows; i++)
            {
                c.contactid = new Key();
                c.contactid.Value = contactIds[i] = Guid.NewGuid();
                Proxy.Create(c);
            }

            string timestamp = System.DateTime.Now.Ticks.ToString();
            string CSVFile = resultDir + @"\PerfContact_" + timestamp + ".csv";
            string SummaryFile = resultDir + @"\Perf_Import_" + noOfRows.ToString() + "Contacts_Update_Summary_" + timestamp + ".log";
            //write logic to create the csv file
            StreamWriter sw = new StreamWriter(CSVFile, false);
            string row = "Contact,Business Phone,Anniversary,Annual Income,Assistant,Assistant Phone,Birthday,Childrens Names,Credit Hold,Department,Description,E-mail,Employee,Fax,Gender,Government,Has Children,Home Phone,Job Title,Last Name,Manager,Manager Phone,Marital Status,Middle Name,First Name,Mobile Phone,Nickname,No. of Children,Pager,Payment Terms,Preferred Day,Role,Salutation,Suffix,Web Site";
            sw.WriteLine(row);
            string clocktick = DateTime.Now.Millisecond.ToString();
            string today = DateTime.Today.ToString();
            for (int i = 1; i <= noOfRows; i++)
            {   //logic to create distinct rows
                row = contactIds[i] + ",11111111," + today + ",234324,Mary,55555555," + today + ",Childrens Names,0,Finance,Have a nice day!!!,a@a.com,24245,44444444,Female,USA,1,22222222,Development Lead,Lastname" + clocktick + i.ToString() + ",David,66666666,Married,Middlename" + clocktick + i.ToString() + ",FinalFirstname" + clocktick + i.ToString() + ",33333333,Julia,4,77777777,Net 30,Monday,Employee,Mrs.,Supremo,www.microsoft.com";
                sw.WriteLine(row);
            }
            sw.Flush();
            sw.Close();

            string configDirKeyPath = "SOFTWARE\\Microsoft\\MSCRM";
            string configDir = null;

            if (Registry.LocalMachine.OpenSubKey(configDirKeyPath) != null)
            {
                RegistryKey regKey = Registry.LocalMachine.OpenSubKey(configDirKeyPath);
                configDir = (string)regKey.GetValue("CRM_Perf_Toolkit_ConfigDir", "c:\\crmstress");
            }
            else
            {
                //setting the default directory of configsettings.xml to c:\crmstress folder
                configDir = "c:\\crmstress";
            }

            string importMapInnerXml = LoadMap(configDir + "\\contact.xml");

            ImportEntityForGivenMapXMLAndCSVFIle(importMapInnerXml, new string[] { "contact" }, new string[] { CSVFile }, true, SummaryFile, noOfRows, 0); ;
        }

        private void ImportExportMaps()
        {
            // Import a map

            string configDirKeyPath = "SOFTWARE\\Microsoft\\MSCRM";
            string configDir = null;

            if (Registry.LocalMachine.OpenSubKey(configDirKeyPath) != null)
            {
                RegistryKey regKey = Registry.LocalMachine.OpenSubKey(configDirKeyPath);
                configDir = (string)regKey.GetValue("CRM_Perf_Toolkit_ConfigDir", "c:\\crmstress");
            }
            else
            {
                //setting the default directory of configsettings.xml to c:\crmstress folder
                configDir = "c:\\crmstress";
            }

            ImportMappingsImportMapRequest importRequest = new ImportMappingsImportMapRequest();
            ImportMappingsImportMapResponse importResponse = new ImportMappingsImportMapResponse();
            importRequest.MappingsXml = LoadMap(configDir + "\\SFMap.xml");
            importRequest.ReplaceIds = true;

            DateTime before = DateTime.Now;
            try
            {
                importResponse = (ImportMappingsImportMapResponse)Proxy.Execute(importRequest);
            }
            catch (SoapException e)
            {
                System.Diagnostics.Trace.WriteLine("Import Mapping Failed:" + e.ToString());
                throw e;
            }
            DateTime after = DateTime.Now;

            double importMapTime = ((TimeSpan)(after - before)).TotalMilliseconds;

            // Export a map

            ExportMappingsImportMapRequest exportRequest = new ExportMappingsImportMapRequest();
            ExportMappingsImportMapResponse exportResponse = new ExportMappingsImportMapResponse();
            exportRequest.ImportMapId = importResponse.ImportMapId;
            before = DateTime.UtcNow;
            try
            {
                exportResponse = (ExportMappingsImportMapResponse)Proxy.Execute(exportRequest);
            }
            catch (SoapException e)
            {
                System.Diagnostics.Trace.WriteLine("Export Mapping Failed:" + e.ToString());
                throw e;
            }
            after = DateTime.UtcNow;

            double exportMapTime = ((TimeSpan)(after - before)).TotalMilliseconds;

            string summaryFile = resultDir + @"\MapImportExport_" + DateTime.Now.Ticks.ToString() + ".log";

            StreamWriter logWriter = new StreamWriter(summaryFile);
            lock (logWriter)
            {
                logWriter.WriteLine("Logging test reult for Map Import/Export ...");
                logWriter.WriteLine("--------------------------------------");
                logWriter.WriteLine("Map Import took {0} milisecond", importMapTime);
                logWriter.WriteLine("Map Export took {0} milisecond", exportMapTime);
                logWriter.Flush();
                logWriter.Close();
            }

        }

        private Guid ImportEntityForGivenMapXMLAndCSVFIle(string importMapInnerXml, string[] entitynames, string[] CSVFiles, string SummaryFile, int expectedSuccessCount, int expectedFailureCount)
        {
            return ImportEntityForGivenMapXMLAndCSVFIle(importMapInnerXml, entitynames, CSVFiles, false, SummaryFile, expectedSuccessCount, expectedFailureCount);
        }

        private Guid ImportEntityForGivenMapXMLAndCSVFIle(string importMapInnerXml, string[] entitynames, string[] CSVFiles, bool isUpdate, string SummaryFile, int expectedSuccessCount, int expectedFailureCount)
        {
            Guid importMapId = CreateImportMapforGivenXML(importMapInnerXml, true);
            if (isUpdate)
                return PerfTestImportUsingFileMapAndCSV(entitynames, CSVFiles, importMapId, true, SummaryFile, expectedSuccessCount, expectedFailureCount);
            else
                return PerfTestImportUsingFileMapAndCSV(entitynames, CSVFiles, importMapId, false, SummaryFile, expectedSuccessCount, expectedFailureCount);
        }

        private Guid PerfTestImportUsingFileMapAndCSV(string[] entityNames, string[] fileNames, Guid importMapId, string SummaryFile, int expectedSuccessCount, int expectedFailureCount)
        {
            return PerfTestImportUsingFileMapAndCSV(entityNames, fileNames, importMapId, false, SummaryFile, expectedSuccessCount, expectedFailureCount);
        }

        private Guid PerfTestImportUsingFileMapAndCSV(string[] entityNames, string[] fileNames, Guid importMapId, bool isUpdate, string SummaryFile, int expectedSuccessCount, int expectedFailureCount)
        {
            DateTime start = DateTime.UtcNow;

            // Create import and import files
            import perfImport = new import();
            StringBuilder name = new StringBuilder();
            foreach (string entityName in entityNames)
                name.Append(entityName);
            perfImport.name = "import" + name.ToString() + DateTime.Now.Ticks.ToString();
            if (isUpdate)
                perfImport.modecode = new Picklist(ImportModeCode.Update);
            else
                perfImport.modecode = new Picklist(ImportModeCode.Create);
            Guid importId = Proxy.Create(perfImport);

            Guid[] importFileIds = new Guid[fileNames.Length];
            for (int i = 0; i < fileNames.Length; i++)
            {
                importfile importFile = new importfile();
                importFile.content = ReadCSV(fileNames[i]);

                importFile.fielddelimitercode = new Picklist(ImportFieldDelimiter.Comma);
                importFile.datadelimitercode = new Picklist(ImportDataDelimiter.Null);
                importFile.isfirstrowheader = new CrmBoolean(true); ;

                Lookup l1 = new Lookup();
                l1.Value = importId;
                importFile.importid = new Lookup("import", importId);
                importFile.sourceentityname = entityNames[i];
                importFile.targetentityname = entityNames[i];

                Lookup l2 = new Lookup();
                l2.Value = importMapId;
                importFile.importmapid = l2;
                importFile.enableduplicatedetection = new CrmBoolean(false);

                importFileIds[i] = Proxy.Create(importFile);
            }

            // Parse the files
            ParseImportRequest parseRequest = new ParseImportRequest();
            parseRequest.ImportId = importId;
            ParseImportResponse parseResponse = (ParseImportResponse)Proxy.Execute(parseRequest);
            
            // Transform parse data
            TransformImportRequest tarnsformRequest = new TransformImportRequest();
            tarnsformRequest.ImportId = importId;
            TransformImportResponse transformResponse = (TransformImportResponse)Proxy.Execute(tarnsformRequest);
            
            // Import transformed data
            ImportRecordsImportRequest importRequest = new ImportRecordsImportRequest();
            importRequest.ImportId = importId;
            ImportRecordsImportResponse importResponse = (ImportRecordsImportResponse)Proxy.Execute(importRequest);
            
            lock (typeof(StreamWriter))
            {
                StreamWriter logWriter = new StreamWriter(SummaryFile);
                logWriter.WriteLine("Logging test reult for Import/Migrate ...");
                logWriter.WriteLine("-----------------------------------------");
                logWriter.WriteLine("Import Id for this test is " + importId.ToString());
                logWriter.WriteLine("Test started at " + start);
                logWriter.Flush();
                logWriter.Close();
            }

            return importId;
        }

        private Guid CreateImportMapforGivenXML(String mappingsXml, bool replaceIds)
        {
            ImportMappingsImportMapRequest request = new ImportMappingsImportMapRequest();
            request.MappingsXml = mappingsXml;
            request.ReplaceIds = replaceIds;
            ImportMappingsImportMapResponse response = new ImportMappingsImportMapResponse();
            try
            {
                response = (ImportMappingsImportMapResponse)Proxy.Execute(request);
                System.Diagnostics.Trace.WriteLine("Pass");
            }
            catch (Exception e)
            {
                System.Diagnostics.Trace.WriteLine("Import Mapping Failed:" + e.ToString());
                throw e;
            }
            return response.ImportMapId;
        }

        private string ReadCSV(string filePath)
        {

            StringBuilder data = new StringBuilder();
            StreamReader reader = new StreamReader(filePath);
            string value = reader.ReadLine();
            while (value != null)
            {
                data.AppendLine(value);

                value = reader.ReadLine();
            }

            return data.ToString();

        }

        #endregion
    }
}
